home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / comm / vt100r29.6 < prev    next >
Internet Message Format  |  1989-10-20  |  72KB

  1. Path: xanth!mcnc!rutgers!ucsd!swrinde!cs.utexas.edu!sun-barr!newstop!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i183:  vt100 - terminal emulator v2.9, Part06/09
  5. Message-ID: <126580@sun.Eng.Sun.COM>
  6. Date: 20 Oct 89 06:10:31 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 2413
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: acs@pccuts.pcc.amdahl.com (Tony Sumrall)
  12. Posting-number: Volume 89, Issue 183
  13. Archive-name: comm/vt100r29.6
  14.  
  15. # This is a shell archive.
  16. # Remove anything above and including the cut line.
  17. # Then run the rest of the file through 'sh'.
  18. # Unpacked files will be owned by you and have default permissions.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar: SHell ARchive
  22. # Run the following text through 'sh' to create:
  23. #    kermit.c
  24. #    kermitproto.c
  25. # This is archive 6 of a 9-part kit.
  26. # This archive created: Thu Oct 19 22:30:31 1989
  27. echo "extracting kermit.c"
  28. sed 's/^X//' << \SHAR_EOF > kermit.c
  29. X/*************************************************************
  30. X * vt100 terminal emulator - KERMIT protocol support
  31. X *            :ts=8
  32. X *
  33. X *    v2.9 ACS - Kermit shouldn't NAK packet 0 but timeout waiting for
  34. X *           send-init then NAK if necessary; terminate each packet with
  35. X  *           EOL only; don't sendstring("\r") but sendchar() it.
  36. X *    v2.8a 880230 ACS - saybye() won't do anything if not in kermit
  37. X *              mode.
  38. X *    v2.7 870825 ACS - Fixed the "multiple-send" problem in
  39. X *              doksend() et al; show status using the *InfoMsg*()
  40. X *              routines in window.c; fixed erroneous calls to
  41. X *              spack() and rpack(); better error handling.
  42. X *    v2.6 870227 DBW - bug fixes for all the stuff in v2.5
  43. X *    v2.5 870214 DBW - more additions (see readme file)
  44. X *    v2.4 861214 DBW - lots of fixes/additions (see readme file)
  45. X *    v2.3 861101 DBW - minor bug fixes
  46. X *    v2.2 861012 DBW - more of the same
  47. X *    v2.1 860915 DBW - new features (see README)
  48. X *         860901 ACS - Added eight bit quoting
  49. X *         860830 Steve Drew Wild card support, err recovry,bugs.
  50. X *         860823 DBW - Integrated and rewrote lots of code
  51. X *         860811 Steve Drew multi filexfer, bugs, status line ect..
  52. X *    v2.0 860809 DBW - Major rewrite
  53. X *    v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes
  54. X *    v1.0 860712 DBW - First version released
  55. X *
  56. X *************************************************************/
  57. X
  58. X#include "vt100.h"
  59. X
  60. X#define MAXPACKSIZ 94        /* Maximum msgpkt size */
  61. X#define CR       13        /* ASCII Carriage Return */
  62. X#define LF       10        /* ASCII line feed */
  63. X#define SP       32        /* ASCII space */
  64. X#define DEL      127        /* Delete (rubout) */
  65. X
  66. X#define MAXTRY      5       /* Times to retry a msgpkt */
  67. X#define MYQUOTE  '#'       /* Quote character I will use */
  68. X#define MYRPTQ     '~'       /* Repeat quote character */
  69. X#define MYEBQ     '&'       /* 8th bit prefix character */
  70. X#define MYPAD       0       /* Number of padding charss I will need */
  71. X#define MYPCHAR    0       /* Padding character I need (NULL) */
  72. X#define MYEOL    '\n'    /* End-Of-Line character I need */
  73. X#define IDOLONG    2    /* I do LONG packets! */
  74. X
  75. X#define tochar(ch)  ((ch) + ' ')
  76. X#define unchar(ch)  ((ch) - ' ')
  77. X#define ctl(ch)     ((ch) ^ 64 )
  78. X
  79. X/* Global Variables */
  80. X
  81. Xint sending,    /* Indicates that we're sending, not receiving */
  82. X    lastpkt,    /* Last successful packet # sent/received */
  83. X    ulp,        /* Using LONG packets */
  84. X    size,    /* Size of present data */
  85. X    osize,    /* Size of last data entry */
  86. X    rpsiz,    /* Maximum receive msgpkt size */
  87. X    spsiz,    /* Maximum send msgpkt size */
  88. X    timint,    /* Time interval to wait */
  89. X    pad,        /* How much padding to send */
  90. X    n,        /* Packet number */
  91. X    tp,        /* total packets */
  92. X    numtry,    /* Times this msgpkt retried */
  93. X    retry,    /* total retries */
  94. X    oldtry,    /* Times previous msgpkt retried */
  95. X    sendabort,    /* flag for aborting send file  */
  96. X    rptflg,    /* are we doing repeat quoting */
  97. X    ebqflg,    /* are we doing 8th bit quoting */
  98. X    notfirst,    /* is this the first file received */
  99. X    first,    /* is this the first time in a file */
  100. X    rpt,        /* current repeat count */
  101. X    next,    /* what is the next character */
  102. X    t;        /* current character */
  103. Xlong totbytes;    /* total bytes xfered on this file */
  104. X
  105. Xchar state,    /* Present state of the automaton */
  106. X    padchar,    /* Padding character to send */
  107. X    eol,        /* End-Of-Line character to send */
  108. X    quote,    /* Quote character in incoming data */
  109. X    rptq,    /* Quote character for repeats */
  110. X    ebq,        /* Quote character for 8th bit quoting */
  111. X    ackpkt[MAXPACKSIZ+20],    /* ACK/NAK packet buffer */
  112. X    *msgpkt = NULL,        /* Message Packet buffer is AllocMem()d */
  113. X    *spackbuf = NULL,    /* Dynamically allocated buffer for spack() */
  114. X    filnam[40],    /* remote file name */
  115. X    snum[10],
  116. X    mainmode[10];
  117. X
  118. XFILE *fp;    /* file for send/receive */
  119. X
  120. Xstatic void spack(), print_our_err(), print_host_err(),
  121. X        dostats(), ClearBuffer();
  122. X
  123. Xchar *
  124. Xgetfname(name)    /* returns ptr to start of file name from spec */
  125. Xchar *name;
  126. X{
  127. X    int l;
  128. X
  129. X    l = strlen(name);
  130. X    while(l && name[l] != '/' && name[l] != ':') l--;
  131. X    if (name[l] == '/' || name[l] == ':') l++;
  132. X    return(name += l);
  133. X}
  134. X
  135. Xdoksend(file,more)
  136. Xchar *file;
  137. Xint more;
  138. X{
  139. X    int amount, c, wild;
  140. X    char *p, **list = NULL;
  141. X
  142. X    msgpkt    = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
  143. X    spackbuf  = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
  144. X    sending = 1;
  145. X    if (!strcmp(file,"$")) { saybye(); return(USERABORT); }
  146. X    p = file;
  147. X    while(*p && *p != '*' && *p != '?') p++;
  148. X    if (*p) {
  149. X    wild = TRUE;
  150. X    list = expand(file, &amount);
  151. X    if (list == NULL) InfoMsg1Line("KERMIT: No wild card match");
  152. X    }
  153. X    else {
  154. X    wild = FALSE;
  155. X    amount = 1;
  156. X    }
  157. X    /*      The "multiple send" problem is brought about by attempting to
  158. X    ** send multiple files in a single "batch" (via globbing, e.g. *.foo)
  159. X    ** to a remote kermit that is NOT in server mode.  A 'Z' packet
  160. X    ** (meaning end-of-file) is sent after each of the files with a 'B'
  161. X    ** packet (meaning end-of-batch) coming after the last 'Z' packet.
  162. X    ** The old code reset the packet # on each iteration.  We do it
  163. X    ** outside of the for loop. */
  164. X    n = lastpkt = 0;
  165. X    ulp = 0;    /* Assume we won't use LONG packets */
  166. X    for (c = 0; c < amount; c++) {
  167. X    if (wild == TRUE) p = list[c];
  168. X        else  p = file;
  169. X    strcpy(filnam,getfname(p));
  170. X    ttime = TTIME_KERMIT;
  171. X    tp = retry = numtry = 0; totbytes = 0L;
  172. X    if ((fp = fopen(p,"r")) == NULL) {
  173. X        InfoMsg2Line("KERMIT: Can't open send file:", p);
  174. X        continue;
  175. X    }
  176. X    strcpy(mainmode,"SEND");
  177. X    ClearBuffer();
  178. X
  179. X    /*  This is another piece of the multiple-send fix.  Sendsw() needs
  180. X    ** to know 1) that this is the first file so it can send a send-init
  181. X    ** packet and 2) if this is the last file so it can send a B packet
  182. X    ** to indicate end-of-batch.  The last piece of the multiple-send fix
  183. X    ** is in sendsw() itself. */
  184. X    if ( sendsw(c == 0, c >= (amount-1)) ) /* Successful send? */
  185. X        ScrollInfoMsg(1);
  186. X    fclose(fp);
  187. X    }
  188. X    free_expand(list);
  189. X    FreeMem(spackbuf,    (long)(MAXLONGPKS+20));
  190. X    FreeMem(msgpkt,    (long)(MAXLONGPKS+20));
  191. X    msgpkt = spackbuf = NULL;
  192. X    return(TRUE);
  193. X}
  194. X
  195. Xdokreceive(file,more)
  196. Xchar *file;
  197. Xint more;
  198. X{
  199. X    int retval;
  200. X
  201. X    msgpkt    = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
  202. X    spackbuf  = (char *)AllocMem((long)(MAXLONGPKS+20), MEMF_PUBLIC|MEMF_CLEAR);
  203. X    ttime = TTIME_KERMIT;
  204. X    sending = 0;
  205. X    if (!strcmp(file,"$")) { saybye(); return(USERABORT); }
  206. X    strcpy(filnam, file);
  207. X    if (server) strcpy(mainmode,"GET");
  208. X    else        strcpy(mainmode,"RECV");
  209. X    tp =  lastpkt = retry = n =  numtry = notfirst = 0; totbytes = 0L;
  210. X    ClearBuffer();
  211. X    retval  = recsw();
  212. X    FreeMem(spackbuf,    (long)(MAXLONGPKS+20));
  213. X    FreeMem(msgpkt,    (long)(MAXLONGPKS+20));
  214. X    msgpkt = spackbuf = NULL;
  215. X    return(retval);
  216. X}
  217. X
  218. Xsendsw(firstfile, lastfile)
  219. Xint firstfile, lastfile; /* Multiple-send fix */
  220. X{
  221. X    char sinit(), sfile(), sdata(), seof(), sbreak();
  222. X    sendabort = 0;
  223. X    /* Multiple-send fix.  If this is the first file of the batch then enter
  224. X    ** send-init state otherwise just enter send-file state. */
  225. X    if(firstfile)
  226. X    state = 'S';
  227. X    else
  228. X    state = 'F';
  229. X    while(TRUE) {
  230. X    switch(state) {
  231. X    case 'S':   state = sinit();  break;
  232. X    case 'F':   state = sfile();  break;
  233. X    case 'D':   state = sdata();  break;
  234. X    case 'Z':   state = seof();   break;
  235. X    case 'B':   if (lastfile || sendabort) {
  236. X            /* Multiple-send fix.  If this is the last file then
  237. X            ** send a B packet to indicate end-of-batch. */
  238. X            state = sbreak();
  239. X            break;
  240. X             }
  241. X             return(TRUE);    /* Otherwise, just return. */
  242. X    case 'C':   if (sendabort) return(FALSE);
  243. X            else return(TRUE);
  244. X    case 'E':   dostats('E',"ERROR");  /* so print the err and abort */
  245. X            print_host_err(ackpkt);
  246. X            return(FALSE);
  247. X    case 'A':   if (timeout == USERABORT) {
  248. X            timeout = GOODREAD;
  249. X            n = (n+1)%64;
  250. X            sendabort = 1;
  251. X            dostats('A',"ABORT");
  252. X            strcpy(msgpkt, "D");
  253. X            state = 'Z';
  254. X            break;
  255. X            }
  256. X            if (timeout == TIMEOUT) dostats('A',"TMOUT");
  257. X            else { /* protocol error dectected by us */
  258. X            dostats('A',"ERROR");
  259. X            print_our_err();
  260. X            }
  261. X            return(FALSE);
  262. X    default:    return(FALSE);
  263. X    }
  264. X    }
  265. X}
  266. X
  267. Xchar sinit()
  268. X{
  269. X    int num, len;
  270. X
  271. X    retry++;
  272. X    if (numtry++ > MAXTRY) return('A');
  273. X    spar(msgpkt);
  274. X
  275. X    spack('S',n,13,msgpkt);
  276. X    switch(rpack(&len,&num,ackpkt)) {
  277. X    case 'N':    return(state);
  278. X    case 'Y':    if (n != num) return(state);
  279. X        rpar(ackpkt, len);
  280. X        if (eol == 0) eol = '\n';
  281. X        if (quote == 0) quote = MYQUOTE;
  282. X        numtry = 0;
  283. X        retry--;
  284. X        n = (n+1)%64;
  285. X        return('F');
  286. X    case 'E':    return('E');
  287. X    case FALSE:    if (timeout == USERABORT) state = 'A';
  288. X        return(state);
  289. X    default:    return('A');
  290. X    }
  291. X}
  292. X
  293. Xchar sfile()
  294. X{
  295. X    int num, len;
  296. X
  297. X    retry++;
  298. X    if (numtry++ > MAXTRY) return('A');
  299. X
  300. X    spack('F',n,strlen(filnam),filnam);
  301. X    switch(rpack(&len,&num,ackpkt)) {
  302. X    case 'N':
  303. X    num = (--num<0 ? 63:num);
  304. X    if (n != num) return(state);
  305. X    case 'Y':
  306. X    if (n != num) return(state);
  307. X    numtry = 0;
  308. X    retry--;
  309. X    n = (n+1)%64;
  310. X    first = 1;
  311. X    size = getpkt();
  312. X    return('D');
  313. X    case 'E':
  314. X    return('E');
  315. X    case FALSE:    if (timeout == USERABORT) state = 'A';
  316. X           return(state);
  317. X    default:
  318. X    return('A');
  319. X    }
  320. X}
  321. X
  322. Xchar sdata()
  323. X{
  324. X    int num, len;
  325. X
  326. X    retry++;
  327. X    if (numtry++ > MAXTRY) return('A');
  328. X
  329. X    spack('D',n,size,msgpkt);
  330. X    switch(rpack(&len,&num,ackpkt)) {
  331. X    case 'N':
  332. X    num = (--num<0 ? 63:num);
  333. X    if (n != num) return(state);
  334. X    case 'Y':
  335. X    if (n != num) return(state);
  336. X    numtry = 0;
  337. X    retry--;
  338. X    n = (n+1)%64;
  339. X    if ((size = getpkt()) == 0) return('Z');
  340. X    return('D');
  341. X    case 'E':
  342. X    return('E');
  343. X    case FALSE: if (timeout == USERABORT) state = 'A';
  344. X           return(state);
  345. X    default:
  346. X    return('A');
  347. X    }
  348. X}
  349. X
  350. Xchar seof()
  351. X{
  352. X    int num, len;
  353. X    retry++;
  354. X    if (numtry++ > MAXTRY) return('A');
  355. X
  356. X/*   if (timeout == USERABORT) {*/    /* tell host to discard file */
  357. X/*    timeout = GOODREAD;    */
  358. X/*      spack('Z',n,1,"D");    */
  359. X/*      }            */
  360. X/*   else            */
  361. X    spack('Z',n,sendabort,msgpkt);
  362. X    switch(rpack(&len,&num,ackpkt)) {
  363. X    case 'N':
  364. X    num = (--num<0 ? 63:num);
  365. X    if (n != num) return(state);
  366. X    case 'Y':
  367. X    if (n != num) return(state);
  368. X    numtry = 0;
  369. X    dostats('Z',"DONE");
  370. X    retry--;
  371. X    n = (n+1)%64;
  372. X    return('B');
  373. X    case 'E':    return('E');
  374. X    case FALSE:    return(state);
  375. X    default:    return('A');
  376. X    }
  377. X}
  378. X
  379. Xchar sbreak()
  380. X{
  381. X    int num, len;
  382. X    retry++;
  383. X    if (numtry++ > MAXTRY) return('A');
  384. X
  385. X    spack('B',n,0,msgpkt);
  386. X    switch (rpack(&len,&num,ackpkt)) {
  387. X    case 'N':
  388. X    num = (--num<0 ? 63:num);
  389. X    if (n != num) return(state);
  390. X    case 'Y':
  391. X    if (n != num) return(state);
  392. X    dostats('B', "DONE");
  393. X    numtry = 0;
  394. X    retry--;
  395. X    n = (n+1)%64;
  396. X    return('C');
  397. X    case 'E':    return('E');
  398. X    case FALSE:    return(state);
  399. X    default:    return ('A');
  400. X    }
  401. X}
  402. X
  403. X/* timeout equals USERABORT so lets end the file and quit  */
  404. X/* when host receives 'Z' packet with "D" in data field he */
  405. X/* should discard the file.                   */
  406. X/*
  407. Xsabort()
  408. X{
  409. X    dostats(' ',"ABORT");
  410. X    n = (n+1)%64;
  411. X    retry--;
  412. X    state = 'Z';
  413. X    while (state == 'Z') state = seof();
  414. X    while (state == 'B') state = sbreak();
  415. X    return(FALSE);
  416. X}
  417. X*/
  418. X
  419. X
  420. Xrecsw()
  421. X{
  422. X    char rinit(), rfile(), rdata();
  423. X    int first_time = 1;
  424. X
  425. X    state = 'R';
  426. X
  427. X    while(TRUE) {
  428. X    switch(state) {
  429. X    case 'R':    ulp = 0;    /* Assume we won't use LONG packets */
  430. X            state = rinit();
  431. X            break;
  432. X    case 'Z':
  433. X    case 'F':    state = rfile(first_time); first_time = 0;
  434. X            break;
  435. X    case 'D':    state = rdata();
  436. X            break;
  437. X    case 'C':    return(TRUE);
  438. X    case 'E':
  439. X    case 'A':   /* easy way to cleanly abort
  440. X            should really send and ACK
  441. X            with "X" in data field and
  442. X            wait for host to abort but
  443. X            not all kermits support
  444. X            this feature.        */
  445. X            if (timeout == USERABORT){
  446. X                /* send an error packet back   */
  447. X                dostats('A',"ABORT");
  448. X                spack('E',n,12,"User aborted");
  449. X                }
  450. X                else if (timeout == TIMEOUT) {
  451. X                /* we timed out waiting */
  452. X                /* will we need to spack here ?*/
  453. X                dostats('A',"TMOUT");
  454. X            }
  455. X            /* must be 'E' from host or we detected a protocol 
  456. X            ** error */
  457. X            else dostats('A',"ERROR");
  458. X
  459. X            if (state == 'E') print_host_err(msgpkt);
  460. X            else if (timeout == GOODREAD) /* tell host why */
  461. X                print_our_err();
  462. X                /* will this kill all files ?*/
  463. X            do  {
  464. X                ttime = 2;
  465. X                readchar();
  466. X            }  while (timeout == GOODREAD);
  467. X            fclose(fp);
  468. X            sendchar('\r');
  469. X            return(FALSE);
  470. X    default:    return(FALSE);
  471. X    }
  472. X    }
  473. X}
  474. X
  475. Xchar rinit()
  476. X{
  477. X    int len, num, temp;
  478. X    retry++;
  479. X    if (numtry++ > MAXTRY) return('A');
  480. X
  481. X    if (server)
  482. X    spack('R',n,strlen(filnam),filnam);
  483. X
  484. X    switch(rpack(&len,&num,msgpkt)) {
  485. X    case 'S':
  486. X    rpar(msgpkt, len);
  487. X    /*   Rpar() will set ulp if we can use long packets.  We can't use
  488. X    ** that value right away cause we've gotta ACK with normal pkts. */
  489. X    temp = ulp; ulp = 0;
  490. X    spar(msgpkt);
  491. X    spack('Y',n,13,msgpkt);
  492. X    ulp = temp;    /* Restore using long pkts flag */
  493. X    oldtry = numtry;
  494. X    numtry = 0;
  495. X    retry--;
  496. X    n = (n+1)%64;
  497. X    return('F');
  498. X    case 'E':
  499. X    return('E');
  500. X    case 'N':        /* Other side NAKed us... */
  501. X    return(state); /* ...so try again      */
  502. X    case FALSE:
  503. X    if (timeout == USERABORT) return('A');
  504. X    if (timeout == TIMEOUT)   return(state); /* Resend Rec-init on a timeout */
  505. X    spack('N',n,0,"");
  506. X    return(state);
  507. X    default:
  508. X    return('A');
  509. X    }
  510. X}
  511. X
  512. Xchar rfile(first_time)
  513. Xint first_time;
  514. X{
  515. X    int num, len, temp;
  516. X    USHORT a, a7, b8;
  517. X    char *fileptr, *buf;
  518. X
  519. X    retry++;
  520. X    if (numtry++ > MAXTRY) return('A');
  521. X
  522. X    switch(rpack(&len,&num,msgpkt)) {
  523. X    case 'S':
  524. X    if (oldtry++ > MAXTRY) return('A');
  525. X    if (num == ((n==0) ? 63:n-1)) {
  526. X        /*   Rpar() will set ulp if we can use long packets.  We can't use
  527. X        ** that value right away cause we've gotta ACK with normal pkts. */
  528. X        temp = ulp; ulp = 0;
  529. X        spar(msgpkt);
  530. X        spack('Y',num,13,msgpkt);
  531. X        ulp = temp;
  532. X        numtry = 0;
  533. X        return(state);
  534. X    }
  535. X    else return('A');
  536. X    case 'Z':
  537. X    if (oldtry++ > MAXTRY) return('A');
  538. X    if (num == ((n==0) ? 63:n-1)) {
  539. X        spack('Y',num,0,"");
  540. X        ScrollInfoMsg(1);
  541. X        numtry = 0;
  542. X        return(state);
  543. X    }
  544. X    else return('A');
  545. X    case 'F':
  546. X    if (num != n) return('A');
  547. X    if(!first_time) {    /* Scroll the Z packet line up */
  548. X        dostats('Z', "DONE");
  549. X        ScrollInfoMsg(1);
  550. X    }
  551. X    buf = msgpkt;
  552. X    fileptr = filnam;
  553. X    while ((a = *buf++) != '\0') { /* Terminator added by rpack() */
  554. X        if (rptflg) {
  555. X        if (a == rptq) {
  556. X            rpt = unchar(*buf++);
  557. X            a = *buf++;
  558. X        }
  559. X        }
  560. X        b8 = 0;
  561. X        if (ebqflg) {        /* 8th-bit prefixing? */
  562. X        if (a == ebq) {        /* Yes, got an 8th-bit prefix? */
  563. X            b8 = 0200;        /* Yes, remember this, */
  564. X            a = *buf++;        /* and get the prefixed character. */
  565. X        }
  566. X        }
  567. X        if (a == quote) {
  568. X        a  = *buf++;
  569. X        a7 = a & 0177;
  570. X        if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
  571. X        }
  572. X        a |= b8;
  573. X        if (rpt == 0) rpt = 1;
  574. X        if (p_mode == 1 && a == '\r') continue;
  575. X        for (; rpt > 0; rpt--) *fileptr++ = a;
  576. X        *fileptr = '\0';    /* Terminate the filename */
  577. X    }
  578. X
  579. X    if (p_convert) {
  580. X        char *p;
  581. X        p = &filnam[0];
  582. X        while (*p) { *p = tolower(*p); p++; }
  583. X    }
  584. X    if (notfirst) {
  585. X        totbytes = 0L;
  586. X        dostats('F',"RECV");
  587. X    }
  588. X    else {    /* is the first file so emit actual file name from host */
  589. X        notfirst++;
  590. X    }
  591. X    if ((fp = fopen(filnam,"w")) == NULL) {
  592. X        InfoMsg2Line("KERMIT: Unable to create file:", filnam);
  593. X        strcpy(msgpkt,"VT100 - Kermit - cannot create file: ");
  594. X        strcat(msgpkt,filnam);
  595. X        spack('E',n,strlen(msgpkt),msgpkt); /* let host know */
  596. X        dostats('E',"ERROR");
  597. X        return ('\0');     /* abort everything */
  598. X    }
  599. X    spack('Y',n,0,"");
  600. X    oldtry = numtry;
  601. X    numtry = 0;
  602. X    retry--;
  603. X    n = (n+1)%64;
  604. X    return('D');
  605. X
  606. X    /* totaly done server sending no more */
  607. X    case 'B':
  608. X    if (num != n) return ('A');
  609. X    spack('Y',n,0,"");
  610. X    dostats('B', "DONE");
  611. X    ScrollInfoMsg(1);
  612. X    retry--;
  613. X    return('C');
  614. X    case 'E':
  615. X    return('E');
  616. X    case FALSE:
  617. X    if (timeout == USERABORT) return('A');
  618. X    spack('N',n,0,"");
  619. X    return(state);
  620. X    default:
  621. X    return ('A');
  622. X    }
  623. X}
  624. X
  625. Xchar rdata()
  626. X{
  627. X    int num, len;
  628. X    retry++;
  629. X    if (numtry++ > MAXTRY) return('A');
  630. X
  631. X    switch(rpack(&len,&num,msgpkt)) {
  632. X    case 'D':
  633. X    if (num != n) {
  634. X        if (oldtry++ > MAXTRY) return('A');
  635. X        if (num == ((n==0) ? 63:n-1)) {
  636. X           spack('Y',num,6,msgpkt);
  637. X           numtry = 0;
  638. X           return(state);
  639. X        }
  640. X        else return('A');
  641. X    }
  642. X    decode();
  643. X    spack('Y',n,0,"");
  644. X    oldtry = numtry;
  645. X    numtry = 0;
  646. X    retry--;
  647. X    n = (n+1)%64;
  648. X    return('D');
  649. X    case 'Z':
  650. X    if (num != n) return('A');
  651. X    spack('Y',n,0,"");
  652. X    n = (n+1)%64;
  653. X    dostats('Z',"DONE");
  654. X    retry--;
  655. X    fclose(fp);
  656. X    return('Z');
  657. X    case 'F':
  658. X    if (oldtry++ > MAXTRY) return('A');
  659. X    if (num == ((n==0) ? 63:n-1)) {
  660. X        spack('Y',num,0,"");
  661. X        numtry = 0;
  662. X        return(state);
  663. X    }
  664. X    case 'E':
  665. X    return('E');
  666. X    case FALSE:
  667. X    if (timeout == USERABORT) return('A');
  668. X    spack('N',n,0,"");
  669. X    return(state);
  670. X    default:
  671. X    return('A');
  672. X    }
  673. X}
  674. X
  675. Xstatic void
  676. Xspack(type,num,len,data)
  677. Xchar type, *data;
  678. Xint num, len;
  679. X{
  680. X    int i;
  681. X    char chksum, t;
  682. X    register char *bufp;
  683. X
  684. X    if(sending && (lastpkt != num)) {
  685. X    tp++;
  686. X    lastpkt = num;
  687. X    }
  688. X    dostats(type,mainmode);
  689. X    bufp = spackbuf;
  690. X    ClearBuffer();
  691. X
  692. X    for (i=1; i<=pad; i++) sendchar(padchar);
  693. X
  694. X    *bufp++ = SOH;
  695. X    if(ulp && len > (MAXPACKSIZ-3))    /* Using long packets */
  696. X    t = tochar(0);
  697. X    else
  698. X    t = tochar(len+3);
  699. X    *bufp++ = t; chksum  = t;
  700. X    t = tochar(num);
  701. X    *bufp++ = t; chksum += t;
  702. X    *bufp++ = type; chksum += type;
  703. X    if(ulp && len > (MAXPACKSIZ-3)) {    /* Using long packets */
  704. X    unsigned int pl = len + 1;
  705. X
  706. X    t = tochar(pl / 95);
  707. X    *bufp++ = t; chksum += t;
  708. X    t = tochar(pl % 95);
  709. X    *bufp++ = t; chksum += t;
  710. X    t = tochar((((chksum&0300) >> 6)+chksum)&077);
  711. X    *bufp++ = t; chksum += t;
  712. X    }
  713. X    for (i=0; i<len; i++) {
  714. X    *bufp++ = data[i]; chksum += data[i];
  715. X    }
  716. X    chksum = (((chksum&0300) >> 6)+chksum)&077;
  717. X    *bufp++ = tochar(chksum);
  718. X    if (eol)
  719. X    *bufp++ = eol; /* Use sender's requested end-of-line */
  720. X    else
  721. X    *bufp++ = '\r';
  722. X    *bufp   = '\0';
  723. X    sendstring(spackbuf);
  724. X}
  725. X
  726. Xrpack(len,num,data)
  727. Xint *len, *num;
  728. Xchar *data;
  729. X{
  730. X    int i, done;
  731. X    char type, cchksum, rchksum;
  732. X    char t = '\0';
  733. X
  734. X    do {
  735. X    t = readchar();
  736. X    if (timeout != GOODREAD) return(FALSE);
  737. X    } while (t != SOH);
  738. X
  739. X    done = FALSE;
  740. X    while (!done) {
  741. X    t = readchar();
  742. X    if (timeout != GOODREAD) return(FALSE);
  743. X    if (t == SOH) continue;
  744. X    cchksum = t;
  745. X    *len = unchar(t)-3;
  746. X    t = readchar();
  747. X    if (timeout != GOODREAD) return(FALSE);
  748. X    if (t == SOH) continue;
  749. X    cchksum += t;
  750. X    *num = unchar(t);
  751. X    t = readchar();
  752. X    if (timeout != GOODREAD) return(FALSE);
  753. X    if (t == SOH) continue;
  754. X    cchksum += t;
  755. X    type = t;
  756. X    if((*len == -3) && ulp) {    /* Using long packets */
  757. X        t = readchar();
  758. X        if (timeout != GOODREAD) return(FALSE);
  759. X        if (t == SOH) continue;
  760. X        cchksum += t;
  761. X        *len = unchar(t)*95;
  762. X        t = readchar();
  763. X        if (timeout != GOODREAD) return(FALSE);
  764. X        if (t == SOH) continue;
  765. X        cchksum += t;
  766. X        *len += unchar(t);
  767. X        (*len)--;
  768. X        t = readchar();
  769. X        if (timeout != GOODREAD) return(FALSE);
  770. X        if (t == SOH) continue;
  771. X        if(unchar(t) != ((((cchksum&0300) >> 6)+cchksum)&077)) return(FALSE);;
  772. X        cchksum += t;
  773. X    }
  774. X    for (i=0; i<*len; i++) {
  775. X        t = readchar();
  776. X        if (timeout != GOODREAD) return(FALSE);
  777. X        if (t == SOH) continue;
  778. X        cchksum = cchksum + t;
  779. X        data[i] = t;
  780. X    }
  781. X    data[*len] = 0;
  782. X    t = readchar();
  783. X    if (timeout != GOODREAD) return(FALSE);
  784. X    rchksum = unchar(t);
  785. X    t = readchar();
  786. X    if (timeout != GOODREAD) return(FALSE);
  787. X    if (t == SOH) continue;
  788. X    done = TRUE;
  789. X    }
  790. X    if(type != 'B' && type != 'Z')
  791. X    dostats(type,mainmode);
  792. X    cchksum = (((cchksum&0300) >> 6)+cchksum)&077;
  793. X    if (cchksum != rchksum) return(FALSE);
  794. X    if(!sending && (*num != lastpkt)) {
  795. X    tp++;
  796. X    lastpkt = *num;
  797. X    }
  798. X    return((int)type);
  799. X}
  800. X
  801. Xgetpkt() {
  802. X    int i,eof;
  803. X
  804. X    static char leftover[10] = { '\0', '\0', '\0', '\0', '\0',
  805. X                '\0', '\0', '\0', '\0', '\0' };
  806. X
  807. X    if (first == 1) {
  808. X    first = 0;
  809. X    *leftover = '\0';
  810. X    t = getc(fp);
  811. X    if (t == EOF) {
  812. X        first = 1;
  813. X        return(size = 0);
  814. X    }
  815. X    totbytes++;
  816. X    }
  817. X    else if (first == -1) {
  818. X    first = 1;
  819. X    return(size = 0);
  820. X    }
  821. X    for (size = 0; (msgpkt[size] = leftover[size]) != '\0'; size++) ;
  822. X    *leftover = '\0';
  823. X    rpt = 0;
  824. X    eof = 0;
  825. X    while (!eof) {
  826. X    next = getc(fp);
  827. X    if (next == EOF) {
  828. X        first = -1;
  829. X        eof   =  1;
  830. X    }
  831. X    else totbytes++;
  832. X    osize = size;
  833. X    encode(t);
  834. X    t = next;
  835. X    if (size == spsiz-3) return(size);
  836. X    if (size > spsiz-3) {
  837. X        for (i = 0; (leftover[i] = msgpkt[osize+i]) != '\0'; i++)
  838. X        ;
  839. X        size = osize;
  840. X        msgpkt[size] = '\0';
  841. X        return(size);
  842. X    }
  843. X    }
  844. X    return(size);
  845. X}
  846. X
  847. Xstatic void
  848. Xencode(a)
  849. Xchar a;
  850. X{
  851. X    int a7,b8;
  852. X
  853. X    if (p_mode == 1 && a == '\n') {
  854. X    rpt = 0;
  855. X    msgpkt[size++] = quote;
  856. X    msgpkt[size++] = ctl('\r');
  857. X    if (size <= spsiz-3) osize = size;
  858. X    msgpkt[size++] = quote;
  859. X    msgpkt[size++] = ctl('\n');
  860. X    msgpkt[size]   = '\0';
  861. X    return;
  862. X    }
  863. X    if (rptflg) {
  864. X    if (a == next && (first == 0)) {
  865. X        if (++rpt < 94) return;
  866. X        else if (rpt == 94) {
  867. X        msgpkt[size++] = rptq;
  868. X        msgpkt[size++] = tochar(rpt);
  869. X        rpt = 0;
  870. X        }
  871. X    }
  872. X    else if (rpt == 1) {
  873. X        rpt = 0;
  874. X        encode(a);
  875. X        if (size <= spsiz-3) osize = size;
  876. X        rpt = 0;
  877. X        encode(a);
  878. X        return;
  879. X    }
  880. X    else if (rpt > 1) {
  881. X        msgpkt[size++] = rptq;
  882. X        msgpkt[size++] = tochar(++rpt);
  883. X        rpt = 0;
  884. X    }
  885. X    }
  886. X    a7 = a & 0177;
  887. X    b8 = a & 0200;
  888. X
  889. X    if (ebqflg && b8) {            /* Do 8th bit prefix if necessary. */
  890. X    msgpkt[size++] = ebq;
  891. X    a = a7;
  892. X    }
  893. X
  894. X    if ((a7 < SP) || (a7==DEL)) {
  895. X    msgpkt[size++] = quote;
  896. X    a = ctl(a);
  897. X    }
  898. X    if (a7 == quote) msgpkt[size++] = quote;
  899. X    if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote;
  900. X
  901. X    if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */
  902. X    msgpkt[size++] = quote;    /* if doing 8th-bit prefixes */
  903. X
  904. X    msgpkt[size++] = a;
  905. X    msgpkt[size] = '\0';
  906. X}
  907. X
  908. Xstatic void
  909. Xdecode()
  910. X{
  911. X    USHORT  a, a7, b8;
  912. X    char *buf;
  913. X
  914. X    buf = msgpkt;
  915. X    rpt = 0;
  916. X
  917. X    while ((a = *buf++) != '\0') { /* Terminator added by rpack() */
  918. X    if (rptflg) {
  919. X        if (a == rptq) {
  920. X        rpt = unchar(*buf++);
  921. X        a = *buf++;
  922. X        }
  923. X    }
  924. X    b8 = 0;
  925. X    if (ebqflg) {             /* 8th-bit prefixing? */
  926. X        if (a == ebq) {         /* Yes, got an 8th-bit prefix? */
  927. X        b8 = 0200;         /* Yes, remember this, */
  928. X        a = *buf++;         /* and get the prefixed character. */
  929. X        }
  930. X        }
  931. X    if (a == quote) {
  932. X        a  = *buf++;
  933. X        a7 = a & 0177;
  934. X        if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
  935. X    }
  936. X    a |= b8;
  937. X    if (rpt == 0) rpt = 1;
  938. X    if (p_mode == 1 && a == '\r') continue;
  939. X    totbytes += rpt;
  940. X    for (; rpt > 0; rpt--) putc(a, fp);
  941. X    }
  942. X    return;
  943. X}
  944. X
  945. Xstatic void
  946. Xspar(data)
  947. Xchar data[];
  948. X{
  949. X    data[0] = tochar(MAXPACKSIZ);
  950. X    data[1] = tochar(TTIME_KERMIT);
  951. X    data[2] = tochar(MYPAD);
  952. X    data[3] = ctl(MYPCHAR);
  953. X    data[4] = tochar(MYEOL);
  954. X    data[5] = MYQUOTE;
  955. X    if ((p_parity > 0) || ebqflg) {       /* 8-bit quoting... */
  956. X    data[6] = MYEBQ;      /* If parity or flag on, send &. */
  957. X    if ((ebq > 0040 && ebq < 0100) || /* If flag off, then turn it on  */
  958. X       (ebq > 0140 && ebq < 0177) || /* if other side has asked us to */
  959. X       (ebq == 'Y')) 
  960. X        ebqflg = 1;
  961. X    }
  962. X    else                    /* Normally, */
  963. X    data[6] = 'Y';                /* just say we're willing. */
  964. X    data[7] = '1';
  965. X    data[8] = MYRPTQ;
  966. X    data[9] = tochar(IDOLONG);    /* Tell 'em I do LONG packets */
  967. X    data[10] = tochar(0);    /* Don't do windows */
  968. X    data[11] = tochar(p_kmaxpack / 95);
  969. X    data[12] = tochar(p_kmaxpack % 95);
  970. X    data[13] = '\0';
  971. X}
  972. X
  973. Xstatic void
  974. Xrpar(data, len)
  975. Xchar data[];
  976. Xint  len;
  977. X{
  978. X    int ospsiz;
  979. X
  980. X    spsiz   = unchar(data[0]);
  981. X    ospsiz  = spsiz;
  982. X    ttime   = unchar(data[1]);
  983. X    pad     = unchar(data[2]);
  984. X    padchar = ctl(data[3]);
  985. X    eol     = unchar(data[4]);
  986. X    quote   = data[5];
  987. X    rptflg  = 0;
  988. X    ebqflg  = 0;
  989. X    if (len >= 6 && data[6] != 0) {
  990. X    ebq = data[6];
  991. X    if ((ebq > 040 && ebq < 0100) ||
  992. X        (ebq > 0140 && ebq < 0177)) ebqflg = 1;
  993. X    else if (((p_parity > 0) || ebqflg) && (ebq == 'Y')) {
  994. X        ebqflg = 1;
  995. X        ebq = '&';
  996. X    }
  997. X    else ebqflg = 0;
  998. X    }
  999. X    if (len >= 8 && data[8] != 0) {
  1000. X    rptq    = data[8];
  1001. X    rptflg  = ((rptq > 040 && rptq < 0100) ||
  1002. X           (rptq > 0140 && rptq < 0177));
  1003. X    }
  1004. X    if(len >= 9 && data[9] != 0) {
  1005. X    int capas;
  1006. X    for(capas=9; data[capas] & 1; capas++) ; /* Skip over continuations */
  1007. X    if((ulp = (data[9] & IDOLONG)) == IDOLONG) {
  1008. X        spsiz = 500; /* Default if no packet size specified */
  1009. X        if(len >= capas+3) {
  1010. X        spsiz = (unchar((data[capas+2])) * 95) + unchar(data[capas+3]);
  1011. X        if(spsiz > MAXLONGPKS)
  1012. X            spsiz = MAXLONGPKS;
  1013. X        else if(spsiz < 10)    /* Reasonable? */
  1014. X            spsiz = 500;
  1015. X        }
  1016. X    }
  1017. X    }
  1018. X}
  1019. X
  1020. Xvoid
  1021. Xsaybye()
  1022. X{
  1023. X   int len,num;
  1024. X
  1025. X   if(msgpkt == NULL)    /* No msgpkt buffer... */
  1026. X    return;        /* ...so just return.  */
  1027. X
  1028. X   if(numreqs != 0)    /* Requester's up... */
  1029. X    Delay(5L);    /* ...so wait for Intuition, just in case. */
  1030. X   spack('G',n,1,"F");  /* shut down server no more files */
  1031. X   rpack(&len,&num,ackpkt);
  1032. X}
  1033. X
  1034. Xstatic void
  1035. Xprint_our_err()
  1036. X{
  1037. X    if (retry > MAXTRY || oldtry > MAXTRY) {
  1038. X    InfoMsg1Line("KERMIT: Too may retries for packet");
  1039. X    strcpy(msgpkt,"VT100 KERMIT: Too many retries for packet");
  1040. X    }
  1041. X    else {
  1042. X    InfoMsg1Line("KERMIT: Protocol Error");
  1043. X    strcpy(msgpkt,"VT100 KERMIT: Protocol Error");
  1044. X    }
  1045. X    spack('E',n,strlen(msgpkt),msgpkt);
  1046. X}
  1047. X
  1048. Xstatic void
  1049. Xprint_host_err(msg)
  1050. Xchar *msg;
  1051. X{
  1052. X    InfoMsg2Line("KERMIT: Host Error:", msg);
  1053. X}
  1054. X
  1055. Xstatic void
  1056. Xdostats(type,stat)
  1057. Xchar type,*stat;
  1058. X{
  1059. X    char *statusform = "%5s %-15.15s Pkt: %4d Retr: %2d Bytes: %6ld Type: %c",
  1060. X     status[80];
  1061. X
  1062. X    if (type == 'Y' || type == 'N' || type == 'G') return;
  1063. X
  1064. X    sprintf(status, statusform, stat, filnam, tp, retry-1,
  1065. X        (LONG)totbytes, type);
  1066. X    InfoMsgNoScroll(status);
  1067. X}
  1068. X
  1069. Xstatic void
  1070. XClearBuffer()
  1071. X{
  1072. X    AbortIO((struct IORequest *)Read_Request);
  1073. X    Wait(1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit);
  1074. X    WaitIO((struct IORequest *)Read_Request);
  1075. X    Read_Request->IOSer.io_Command = CMD_CLEAR;
  1076. X    DoIO((struct IORequest *)Read_Request);
  1077. X    Read_Request->IOSer.io_Command = CMD_READ;
  1078. X    SendIO((struct IORequest *)Read_Request);
  1079. X}
  1080. SHAR_EOF
  1081. echo "extracting kermitproto.c"
  1082. sed 's/^X//' << \SHAR_EOF > kermitproto.c
  1083. X/*        :ts=8                        */
  1084. X
  1085. X/* WARNING -- This C source program generated by Wart preprocessor. */
  1086. X/* Do not edit this file; edit the Wart-format source file instead, */
  1087. X/* and then run it through Wart to produce a new C source file.     */
  1088. X
  1089. X/* Wart Version Info: */
  1090. Xchar *wartv = "Wart Version 1A(005) Jan 1988";
  1091. X
  1092. X/*
  1093. X * A completely new C Kermit module.
  1094. X *
  1095. X * Based on code from Frank Da Cruz's excellent book, _Kermit: A File
  1096. X * Transfer Protocol_, Digital Press, 1986.
  1097. X *
  1098. X * As this code is almost entirely from said book, it is certainly covered
  1099. X * by that book's copyright.  Basically, this means the code is freely
  1100. X * distributable, and can be used in a commercial program provided such
  1101. X * use does not increase the program's cost to the purchaser beyond a small
  1102. X * handling fee.
  1103. X *
  1104. X * Stephen Walton, swalton@solar.stanford.edu
  1105. X * Dept. of Physics and Astronomy
  1106. X * California State University, Northridge
  1107. X * Northridge, CA 91330
  1108. X *
  1109. X *            ORGANIZATION
  1110. X *
  1111. X *  This file is in three pieces, and could probably be broken into
  1112. X * two files.  Leading off are #DEFINE's and declarations of
  1113. X * global and external variables.  Following are the unmodified sources
  1114. X * from The Book.   Then are the z* file-handling routines written using
  1115. X * standard Unix-style (almost ANSI C) file routines.
  1116. X *
  1117. X * I make no apologies for the organization; my primary goals were (1) to
  1118. X * use the unmodified book source except for errors found by Lint, and
  1119. X * (2) to allow this file to be plugged into an otherwise unmodified
  1120. X * terminal program for the Commodore Amiga computer called VT100.  The
  1121. X * comments starting with the string "/*lint" are for the Lint program
  1122. X * of Gimpel Software, available for the Commodore Amiga and MS-DOS
  1123. X * machines.  I highly recommend it.
  1124. X *
  1125. X * A few words about style herein.  Both "book Kermit" and the official
  1126. X * C Kermit release make extensive use of global variables to set various
  1127. X * options and keep track of what is going on.  I don't like this, but
  1128. X * since example source code must be part of the Kermit specification,
  1129. X * I chose to keep that organization.  There are several places where I
  1130. X * I have tried to modularize things better.  First of all, everything
  1131. X * which is not needed outside of this file is declared "static".  Second,
  1132. X * I have kept the book Kermit code pretty much intact, except for some lint
  1133. X * related things and one extra convention:  tmsg() appends characters to
  1134. X * an existing status line, but tmsgl() is required to force that output to
  1135. X * be seen.  Hence, I've changed the last in each series of tmsg() calls to
  1136. X * tmsgl().
  1137. X */
  1138. X
  1139. X
  1140. X/*
  1141. X * Revision History--Versions 0 through 1 never left me.
  1142. X *
  1143. X * Version 0.5--Created and linted.
  1144. X * Version 0.6--Added RESUME to handling of "unknown packets".
  1145. X *          --Added proto() function to wrap around wart() for handling
  1146. X *        of startup and cleanup functions.
  1147. X *          --Changed handling of timeouts in input():  instead of an
  1148. X *        error("Timeout") call, it puts the "Timeout" message in
  1149. X *        the data field and pretends it read an 'E' packet.
  1150. X * Version 0.7--Fixed a problem with rpsiz and MAXRP.  I had set rpsiz
  1151. X *        to MAXRP in rpar() and was calling ttinl() with a max
  1152. X *        argument of MAXRP, which resulted in truncated packets;
  1153. X *        to wit, MAXRP+1 characters could come into ttinl counting
  1154. X *        the eol.  Created defines DRPSIZ/DSPSIZ for default values
  1155. X *        for rpsiz and spsiz, and increased MAXRP.
  1156. X *          --Changed rcvpkt, sndpkt, and data so that they are pointers
  1157. X *        instead of static arrays, and allocate and de-allocate
  1158. X *        them in proto().
  1159. X * Version 0.8--Added client support.  To make a Get
  1160. X *        command, point the char *cmarg at the remote file
  1161. X *        specification and set the start state to 'r'
  1162. X *        (extern char start in the calling file).
  1163. X * Version 0.9--Added long packet support.  This required adding an extern
  1164. X *        int urpsiz which is set to the desired receive packet size
  1165. X *        by the user interface.
  1166. X *          --Since the above required using the capas, I also added the
  1167. X *        code from C Kermit 4E(070) for negotiating window size
  1168. X *        in rpar() and spar(). Of course, we don't do windows yet.
  1169. X *          --Fixed a bug which is also part of C Kermit 4E(070).
  1170. X *        If we tell the sender that we can receive a packet
  1171. X *        of size MAXRP, the packet can contain as many as
  1172. X *        MAXRP+5 characters, counting the EOL and extended
  1173. X *        headers.  So rpack() must be able to handle somewhat
  1174. X *        more characters than the actual maximum packet length.
  1175. X *        I defined MAXRP here to be 1024, but only allow
  1176. X *        rpsiz in proto() to be MAXRP-20.
  1177. X * Version 0.95--Added code to gracefully abort transfer.  This works
  1178. X *        via the cx and cz external variables and the state 'a'.
  1179. X * Version 1.0--Unleashed upon the world.
  1180. X *        
  1181. X */
  1182. X
  1183. X/*
  1184. X * Run this through the Wart preprocessor which comes with C Kermit.
  1185. X */
  1186. X
  1187. X#include "kermitproto.h"
  1188. X
  1189. Xstatic void decstr(), rinit(), error(), tinit(), spar(), zrtol(), zltor();
  1190. X
  1191. X/*
  1192. X * Here are the variables which need to be set to startup values, and which
  1193. X * also can be freely changed between protocol transfers.  At first I thought
  1194. X * to declare them all "extern" in order to force definition elsewhere.
  1195. X * On reflection, it makes sense to both declare them here and set them to
  1196. X * their default startup values.  Thus they can be ignored outside of this
  1197. X * module if you so desire.
  1198. X *
  1199. X * Note that the names are very systematic:  Names beginning with "r" have
  1200. X * to do with values I use for received packets;  those beginning with "s"
  1201. X * are values I use for sending packets.  Also note we set some, others are
  1202. X * set for us.  I have made the ones we get in spar() static (local),
  1203. X * and the ones we send in rpar() global.
  1204. X *
  1205. X * First the ints.
  1206. X */
  1207. X
  1208. Xint    cx = 0,
  1209. X    cz = 0,        /* Flags for aborting transfers.  cx (control-X)*
  1210. X             * is set to 1 if an abort of the current file    *
  1211. X             * is desired, cz (control-Z) if an abort of    *
  1212. X             * an entire batch transfer is desired.        */
  1213. X    rpsiz = MAXRP,    /* Maximum packet size                */
  1214. X            /* Like most of the receive packet parameters,    *
  1215. X             * this one is actually set by the sender.  But    *
  1216. X             * since the sender has the option to not send    *
  1217. X             * these, we must initialize to "reasonable"    *
  1218. X             * defaults.                    */
  1219. X    bctr,        /* Block check type to request.            */
  1220. X    limit = 5,    /* Retry limit on receive            */
  1221. X    warn = 0,    /* 1 for warn before overwriting files        */
  1222. X    rpadn = 0,    /* Number of pad characters I require.        */
  1223. X    rtimo = 10;    /* How long I want you to wait before you    *
  1224. X             * you time me out.                */
  1225. X
  1226. Xchar    rmark = '\1',    /* Start of packet marker for receive        */
  1227. X    reol = '\r',    /* End of packet marker for receive        */
  1228. X    start = 0,    /* Start state                    */
  1229. X    sctlq = '#',    /* Control character quote character for send    */
  1230. X    rpadc = '\0';    /* Pad character I want you to use        */
  1231. X
  1232. X/*
  1233. X * Variables which MUST be set by the external interface.
  1234. X */
  1235. Xextern int
  1236. X    parity,        /* 0 for no parity--need for proper 8th-bit quote */
  1237. X    text,        /* Flag 1 for text file, 0 for binary file    */
  1238. X    urpsiz;        /* Maximum receive packet size user wants.    */
  1239. X
  1240. Xextern char
  1241. X    *cmarg;        /* Character string containing Kermit server cmd */
  1242. X
  1243. X/*
  1244. X * In a fit of cleverness, here are some macro defines for variables we *
  1245. X * aren't currently using. Only now we tell Lint to ignore constant    *
  1246. X * Booleans!
  1247. X */
  1248. X
  1249. X/*lint -e506 */
  1250. X
  1251. X#define local 1        /* Local mode flag--that is, I'm on your end    */
  1252. X#define server 0    /* We are never server                */
  1253. X#define delay 0        /* Time to delay before sending first packet    */
  1254. X#define xpkt 0        /* Send X packet instead of F?            */
  1255. X
  1256. X/*
  1257. X * This block of defines is strictly internal flags of various kinds.    *
  1258. X * I hope to Grid that I've got them all.  Someday this will be cleaner *
  1259. X */
  1260. Xstatic int
  1261. X    spsiz = DSPSIZ,    /* Maximum send packet size            */
  1262. X    wsize = MAXWS,    /* Maximum window size                */
  1263. X    sndpkl,        /* Size of packet currently being attempted    */
  1264. X    filcnt,        /* Number of files transferred so far        */
  1265. X    bctu = 1,    /* Block check type to use            */
  1266. X    rqf,        /* Flag for 8th bit quote negotiations        */
  1267. X    ebq = '&',    /* 8th-bit prefix                */
  1268. X    ebqflg = 0,    /* 8th-bit quoting flag                */
  1269. X    xflag,        /* Output to screen for generic server commands    */
  1270. X    rq = 0,        /* Received 8bq bid                */
  1271. X    sq = 'Y',    /* Sent 8bq bid                    */
  1272. X    rpt = 0,    /* Repeat count                    */
  1273. X    rptq = '~',    /* Repeat prefix                */
  1274. X    rptflg = 0,    /* Repeat processing flag            */
  1275. X    capas = 10,    /* Final position of inbound capas mask        */
  1276. X    atcapr = 0,    /* Attribute capability requested        */
  1277. X    atcapu = 0,    /* Attribute capability used            */
  1278. X    swcapr = 0,    /* Sliding windows capability requested        */
  1279. X    swcapu = 0,    /* Sliding windows capability used        */
  1280. X    lpcapr = 0,    /* Long packets capability requested        */
  1281. X    lpcapu = 0,    /* Long packets capability used            */
  1282. X    rsn,        /* Received sequence number            */
  1283. X    seq = 0,    /* Current sequence number            */
  1284. X    maxsiz,        /* Maximum data size for packet            */
  1285. X    rln,        /* Length of received data field        */
  1286. X    size,        /* Current size of output packet data        */
  1287. X    osize,        /* Previous output packet data size        */
  1288. X    first = 0,    /* Some kind of lookahead flag            */
  1289. X    stimo = 5,    /* Timeout interval for me to use        */
  1290. X    spadn = 0;    /* Number of pad characters for me to use    */
  1291. X
  1292. X#define atcapb 8    /* Attribute capability bit            */
  1293. X#define swcapb 4    /* Sliding windows capability bit        */
  1294. X#define lpcapb 2    /* Long packets capability bit            */
  1295. X#define closif zclosi    /* I use closif() to close the input file in    *
  1296. X             * case it needs to be more complex later, but    *
  1297. X             * for now it just calls the z routine.        */
  1298. X
  1299. Xstatic char
  1300. X    smark = '\1',    /* Start of packet marker for send        */
  1301. X    spadc = '\0',    /* Pad character to use on sending        */
  1302. X    seol = '\r',    /* End of packet marker for sending        */
  1303. X    rctlq = '#',    /* Control character quote char for receiving    */
  1304. X    filnam[50],    /* Current file name                */
  1305. X    ssc,        /* Start server command                */
  1306. X    *sndpkt,    /* Send packet.                    */
  1307. X    *rcvpkt,    /* Receieve packet.                */
  1308. X    *data,        /* Data to send/receive before encode/decode    */
  1309. X    *rdatap,    /* Pointer to null-terminated data field    */
  1310. X    *isp = NULL,    /* Pointer to characters in memory        */
  1311. X    *osp = NULL;    /* Output string pointer            */
  1312. X
  1313. X/*
  1314. X * Forward declarations.  Soon to be prototypes if the ANSI standard
  1315. X * committee keeps its promises.
  1316. X */
  1317. Xint input(), spack(), ack();
  1318. Xchar *rpar();
  1319. X
  1320. X/*
  1321. X * External routines provided.
  1322. X */
  1323. X
  1324. Xextern int ttinl(), ttol(), gnfile();
  1325. Xextern void ttflui(), tchar(), tmsg(), tmsgl(), sleep();
  1326. X
  1327. X#define ERR(s) error(s); RESUME
  1328. X#define RESUME return
  1329. X
  1330. X/*lint -save -e525 -e527    We don't care how Wart formats!        */
  1331. X
  1332. X#define ssfil 1
  1333. X#define ssdat 2
  1334. X#define sseot 3
  1335. X#define srini 4
  1336. X#define srfil 5
  1337. X#define srdat 6
  1338. X#define sipkt 7
  1339. X#define srgen 8
  1340. X
  1341. X#define BEGIN state =
  1342. X
  1343. Xint state = 0;
  1344. X
  1345. Xvoid
  1346. Xwart()
  1347. X{
  1348. X    int c,actno;
  1349. X    extern int tbl[];
  1350. X    while (1) {
  1351. X    c = input();
  1352. X    if ((actno = tbl[c + state*128]) != -1)
  1353. X        switch(actno) {
  1354. Xcase 1:
  1355. X    {                    /* - Start State - */
  1356. X    tinit();                /* Initialize transaction */
  1357. X    if (sinit('S') < 0) { ERR("sinit"); }    /* Build, send Send-Init. */
  1358. X    else {                /* If successful, */
  1359. X    filcnt = 0;            /* initialize file counter */
  1360. X    BEGIN ssfil;            /* and switch to ssfil state. */
  1361. X    }
  1362. X}
  1363. X    break;
  1364. Xcase 2:
  1365. X    { tinit(); rinit(); BEGIN srini; }
  1366. X    break;
  1367. Xcase 3:
  1368. X    {                    /* Get */
  1369. X    tinit(); ssc = 0;
  1370. X    if (sinit('I') < 0) { ERR("sinit"); }
  1371. X    else BEGIN sipkt;
  1372. X}
  1373. X    break;
  1374. Xcase 4:
  1375. X    {                    /* Host */
  1376. X    tinit(); ssc = 'C';
  1377. X    if (sinit('I') < 0) { ERR("sinit"); }
  1378. X    else BEGIN sipkt;
  1379. X}
  1380. X    break;
  1381. Xcase 5:
  1382. X    {                    /* Generic */
  1383. X    tinit(); ssc = 'G';
  1384. X    if (sinit('I') < 0) { ERR("sinit"); }
  1385. X    else BEGIN sipkt;
  1386. X}
  1387. X    break;
  1388. Xcase 6:
  1389. X    {                    /* Immediate protocol abort */
  1390. X    spack('E', seq, "User aborted protocol", 21);
  1391. X    closif();  closof(1);        /* Close files, deleting output */
  1392. X    RESUME;
  1393. X}
  1394. X    break;
  1395. Xcase 7:
  1396. X    {                /* - Send File State - */
  1397. X    if (filcnt++ == 0) spar(rdatap);    /* Set parameters if 1st time */
  1398. X    cx = 0;                /* Reset file interruption flag */
  1399. X    bctu = bctr;            /* Switch to negotiated block check */
  1400. X    /* Is there a file to send in an uncancelled batch? */
  1401. X    if (!cz && gnfile(filnam, sizeof(filnam)) > 0) {
  1402. X    if (sfile() < 0) { ERR("sfile"); }    /* Yes, open it, send F packet */
  1403. X    else BEGIN ssdat;        /* and if no error, switch state. */
  1404. X    } else {                /* No (more) files to send */
  1405. X    if (seot() < 0) { ERR("seot"); }    /* so send B packet */
  1406. X    else BEGIN sseot;        /* and switch to sseot state. */
  1407. X    }
  1408. X}
  1409. X    break;
  1410. Xcase 8:
  1411. X    {                /* - Send Data State - */
  1412. X    int x;
  1413. X    if (rln == 1 && *rdatap == 'X')    /* Did ACK contain X as data? */
  1414. X    cx = 1;                /* Yes, set control-x flag. */
  1415. X    else if (rln == 1 && *rdatap == 'Z') /* Did ACK contain Z as data? */
  1416. X    cz = 1;                /* Yes set control-z flag. */
  1417. X    /* Check here for cancellation of transfer and data left to send. */
  1418. X    if (cx || cz || (x = sdata()) == 0) {
  1419. X    if (seof((cx | cz) ? "D" : "") < 0) {    /* If not, send Z packet. */
  1420. X        ERR("seof");
  1421. X    }
  1422. X    else BEGIN ssfil;        /* and go back to ssfil state. */
  1423. X    } else if (x < 0) { ERR("sdata"); }    /* Handle file i/o errors. */
  1424. X}
  1425. X    break;
  1426. Xcase 9:
  1427. X    { RESUME; }
  1428. X    break;
  1429. Xcase 10:
  1430. X    {
  1431. X    spar(rdatap);
  1432. X    (void) ack1(rpar());
  1433. X    bctu = bctr;
  1434. X    BEGIN srfil;
  1435. X}
  1436. X    break;
  1437. Xcase 11:
  1438. X    { (void) ack(); RESUME; }
  1439. X    break;
  1440. Xcase 12:
  1441. X    { if (rcvfil() < 0) { ERR("rcvfil"); } else { (void) ack(); BEGIN srdat; } }
  1442. X    break;
  1443. Xcase 13:
  1444. X    {
  1445. X   if (cx)
  1446. X    ack1("X");
  1447. X   else if (cz)
  1448. X    ack1("Z");
  1449. X   else {
  1450. X    if (decode() < 0) { ERR("decode"); } else (void) ack();
  1451. X   }
  1452. X}
  1453. X    break;
  1454. Xcase 14:
  1455. X    {
  1456. X    /* Discard output file if the sender tells us so. */
  1457. X    if (closof(cx || cz || (rln == 1 && *rdatap == 'D')) < 0) {
  1458. X    ERR("error closing file");
  1459. X    } else {
  1460. X    (void) ack(); BEGIN srfil;
  1461. X    }
  1462. X}
  1463. X    break;
  1464. Xcase 15:
  1465. X    {            /* Got ACK for I packet */
  1466. X    spar(rdatap);        /* Set parameters from it */
  1467. X    start = 'E';        /* Force entry into next state */
  1468. X}
  1469. X    break;
  1470. Xcase 16:
  1471. X    {            /* Got E for I packet */
  1472. X    if (ssc) {
  1473. X    if (scmd(ssc,cmarg) < 0) { ERR("scmd"); }
  1474. X    else BEGIN srgen;
  1475. X    } else {
  1476. X    if (scmd('R',cmarg) < 0) { ERR("scmd"); }
  1477. X    else BEGIN srini;
  1478. X    }
  1479. X}
  1480. X    break;
  1481. Xcase 17:
  1482. X    { xflag = 1; decode(); RESUME; }
  1483. X    break;
  1484. Xcase 18:
  1485. X    { xflag = 1; ack(); BEGIN srdat; }
  1486. X    break;
  1487. Xcase 19:
  1488. X    { error(rdatap);
  1489. X    (void) closif();
  1490. X    (void) closof(1);        /* close files, discarding output */
  1491. X    RESUME; }
  1492. X    break;
  1493. Xcase 20:
  1494. X    { error("Unexpected packet type"); RESUME; }
  1495. X    break;
  1496. X
  1497. X        }
  1498. X    }
  1499. X}
  1500. X
  1501. Xint tbl[] = {
  1502. X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1503. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1504. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1505. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1506. X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1507. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1508. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1509. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1510. X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1511. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1512. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1513. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1514. X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1515. X20, 20, 20, 20, 20, 20, 20, 20, 20,  7, 20, 20, 20, 20, 20, 20, 
  1516. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1517. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1518. X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1519. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1520. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1521. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1522. X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1523. X20, 20, 20, 20, 20, 20, 20, 20, 20,  8, 20, 20, 20, 20, 20, 20, 
  1524. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1525. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1526. X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1527. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1528. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1529. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1530. X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1531. X20, 20, 20, 20, 20, 20, 20, 20, 20,  9, 20, 20, 20, 20, 20, 20, 
  1532. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1533. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1534. X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1535. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1536. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1537. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1538. X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1539. X20, 20, 20, 10, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1540. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1541. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1542. X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1543. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1544. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1545. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1546. X20, 20, 11, 20, 20, 19, 12, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1547. X20, 20, 20, 20, 20, 20, 20, 20, 18, 20, 20, 20, 20, 20, 20, 20, 
  1548. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1549. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1550. X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1551. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1552. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1553. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1554. X20, 20, 20, 20, 13, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1555. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 14, 20, 20, 20, 20, 20, 
  1556. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1557. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1558. X-1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1559. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1560. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1561. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1562. X20, 20, 20, 20, 20, 16, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1563. X20, 20, 20, 20, 20, 20, 20, 20, 20, 15, 20, 20, 20, 20, 20, 20, 
  1564. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1565. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1566. X 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1567. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1568. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1569. X20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1570. X20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1571. X20, 20, 20, 10, 20, 20, 20, 20, 18, 17, 20, 20, 20, 20, 20, 20, 
  1572. X20,  6, 20,  4, 20, 20, 20,  5, 20, 20, 20, 20, 20, 20, 20, 20, 
  1573. X20, 20,  3,  1, 20, 20,  2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 
  1574. X};
  1575. X
  1576. X
  1577. X/*lint -restore */
  1578. X
  1579. X/*
  1580. X * First, some handy macros.
  1581. X */
  1582. X
  1583. X#define tochar(c) ((c) + 32)
  1584. X#define unchar(c) ((c) - 32)
  1585. X#define ctl(c) ((c) ^ 64)
  1586. X
  1587. Xstatic
  1588. Xint
  1589. Xinput() {                /* Return packets    */
  1590. X   int type, try;
  1591. X
  1592. X    if (start != 0) {            /* Start state in effect? */
  1593. X    type = start;            /* Yes, call it a packet type, */
  1594. X    start = 0;            /* nullify the start state, */
  1595. X    return(type);            /* and return the type. */
  1596. X    }
  1597. X    type = rpack();            /* No start state, read a packet. */
  1598. X
  1599. X    for (try = 0; rsn != seq || strchr("TQN",type); try++) {
  1600. X    if (try > limit) {        /* If too mahy tries, */
  1601. X        strcpy(data, "Timed out");    /* give up */
  1602. X        rdatap = data;        /* Make up pretend 'E' packet */
  1603. X        return('E');        /* and return it */
  1604. X    }
  1605. X    if (type == 'N' && rsn == ((seq + 1) & 63)) {
  1606. X                    /* NAK for next packet */
  1607. X        return('Y');        /* is ACK for current. */
  1608. X    } else {            /* Otherwise, */
  1609. X        (void) resend();        /* resend previous packet. */
  1610. X    }
  1611. X    type = rpack();            /* Try to read response. */
  1612. X    }
  1613. X    ttflui();                /* Got a good one, clear buffer. */
  1614. X    return(type);            /* Return its type. */
  1615. X}
  1616. X
  1617. Xstatic void
  1618. Xnxtpkt() {
  1619. X    seq = (seq + 1) & 63;        /* Next packet number, mod 64 */
  1620. X}
  1621. X
  1622. Xstatic void
  1623. Xtinit() {                /* Transaction initialization */
  1624. X    seq = 0;                /* Start off with packet 0 */
  1625. X    ebqflg = 0;                /* 8-bit quoting off */
  1626. X    sq = 'Y';                /* Normal 8-bit quote bid */
  1627. X    rqf = -1;                /* Flag other's bid not yet seen */
  1628. X    rptflg = 0;                /* No repeat counts by default */
  1629. X    bctu = 1;                /* Block check to use back to 1 */
  1630. X    xflag = 0;                /* Output normally to file */
  1631. X    osp = NULL;                /* ... */
  1632. X    *filnam = *sndpkt = *rcvpkt = '\0';  /* Clear string buffers */
  1633. X}
  1634. X
  1635. Xstatic void
  1636. Xerror(s) char *s; {            /* Fatal error */
  1637. X    if (local) {            /* If in local mode */
  1638. X    tmsg("Fatal error: ");        /* Type message on console */
  1639. X    tmsgl(s);
  1640. X    } else {                /* Otherwise, */
  1641. X    (void) spack('E',seq,strlen(s),s); /* Send in error packet. */
  1642. X    }
  1643. X}
  1644. X
  1645. Xstatic
  1646. Xack() {
  1647. X    int x;                /* Empty acknowledgement */
  1648. X    x = spack('Y',seq,0,"");        /* Send the packet */
  1649. X    nxtpkt();                /* Increment the packet number */
  1650. X    return(x);
  1651. X}
  1652. X
  1653. Xstatic
  1654. Xack1(s) char *s; {
  1655. X    int x;                /* Acknowledgement with data */
  1656. X    x = spack('Y',seq,strlen(s),s);    /* Send the packet */
  1657. X    nxtpkt();                /* Increment packet number */
  1658. X    return(x);
  1659. X}
  1660. X
  1661. Xstatic
  1662. Xnak() {                    /* Negative acknowledgement */
  1663. X    return(spack('N',seq,0,""));    /* Never has data! */
  1664. X}
  1665. X
  1666. X/* Functions used by file sender. */
  1667. X
  1668. X/* sinit()--start the transaction by filling in the initialization string
  1669. X * and sending it in an S packet.
  1670. X */
  1671. X
  1672. Xstatic
  1673. Xsinit(c) char c; {
  1674. X    char *s;
  1675. X    s = rpar();
  1676. X    if (local == 0 && c == 'S' && server == 0) {
  1677. X    tmsgl("Escape back to local system, give RECEIVE command...");
  1678. X    sleep(delay);
  1679. X    }
  1680. X    return(spack(c,seq,strlen(s),s));
  1681. X}
  1682. X
  1683. X/*
  1684. X * scmd() -- send a preformatted Kermit server command string.
  1685. X */
  1686. Xstatic int
  1687. Xscmd(t, s) char t, *s; {    /* Send a packet of the given type */
  1688. X    encstr(s);            /* Encode the command string */
  1689. X    spack(t,seq,size,data);
  1690. X    return 0;
  1691. X}
  1692. X
  1693. X/* rinit() -- do whatever is needed to initialize receive.  A no-op now,
  1694. X * but may later initialize counters and so on.
  1695. X */
  1696. Xstatic void
  1697. Xrinit()
  1698. X{}
  1699. X
  1700. X/* sfile() -- open the file and send the File-Header packet.  Assumes that
  1701. X * the global string pointer filnam references the file name.
  1702. X */
  1703. X
  1704. Xstatic
  1705. Xsfile() {
  1706. X    int x;
  1707. X    char pktnam[50];
  1708. X    if (zopeni(filnam) < 0)        /* Try to open file. */
  1709. X    return -1;
  1710. X    zltor(filnam,pktnam);        /* OK, convert name. */
  1711. X    x = encstr(pktnam);            /* Encode the result */
  1712. X    if (local) {            /* If in local mode, */
  1713. X    tmsg("Sending ");        /* let user know we're */
  1714. X    tmsg(filnam);            /* sending this file */
  1715. X    tmsg(" as ");            /* under */
  1716. X    tmsgl(pktnam);            /* this name */
  1717. X    }
  1718. X    first = 1;                /* Flag beginning of file */
  1719. X    maxsiz = spsiz - (bctr + 3);    /* Maximum data length */
  1720. X    nxtpkt();                /* Increment packet number */
  1721. X    return(spack((xpkt ? 'X' : 'F'),seq,x,data)); /* Send packet */
  1722. X}
  1723. X
  1724. X/* sdata() -- get next packet's worth of data */
  1725. X
  1726. Xstatic
  1727. Xsdata() {
  1728. X    int x;
  1729. X    if ((x = getpkt(maxsiz)) == 0)    /* If no data left to send, */
  1730. X    return(0);            /* return EOF indication. */
  1731. X    nxtpkt();
  1732. X    return(spack('D',seq,x,data));    /* Send the data packet */
  1733. X}
  1734. X
  1735. X/* seof -- close the input file and send a Z packet. */
  1736. X
  1737. Xstatic
  1738. Xseof(s) char *s; {
  1739. X   if (closif() < 0)            /* Try to close the file. */
  1740. X    return -1;            /* On error, return failure. */
  1741. X    else {                /* Otherwise, */
  1742. X    if (local) tmsgl("OK");        /* if local, reassure user. */
  1743. X    nxtpkt();
  1744. X    return(spack('Z',seq,strlen(s),s));    /* Send Z packet */
  1745. X    }
  1746. X}
  1747. X
  1748. X/* seot -- send B packet. */
  1749. X
  1750. Xstatic
  1751. Xseot() {
  1752. X    nxtpkt();
  1753. X    if (local) tmsgl("Done");
  1754. X    return(spack('B',seq,0,""));
  1755. X}
  1756. X
  1757. Xstatic
  1758. Xrcvfil() {                /* Receive a file */
  1759. X    char myname[50];
  1760. X    decstr(filnam);            /* Decode name */
  1761. X    zrtol(filnam,myname,warn);        /* Convert to local form. */
  1762. X    if (zopeno(myname) < 0)
  1763. X    return -1;
  1764. X    else {                /* File open OK, give message. */
  1765. X    if (local && !xflag) {
  1766. X        tmsg("Receiving "); tmsg(filnam); tmsg(" as "); tmsgl(myname);
  1767. X    }
  1768. X    return 0;
  1769. X    }
  1770. X}
  1771. X
  1772. Xstatic
  1773. Xclosof(nokeep) int nokeep; {        /* Close output file, but */
  1774. X    if (xflag) return 0;        /* not if it's the screen. */
  1775. X    if (zcloso(nokeep) < 0)
  1776. X    return -1;
  1777. X    return 0;
  1778. X}
  1779. X
  1780. Xstatic
  1781. Xspack(type,n,len,d) char type, *d; int n, len; {
  1782. X    int i = 0, j, k;
  1783. X
  1784. X    for (i = 0; i < spadn; i++)
  1785. X    sndpkt[i] = spadc;        /* Do requested padding */
  1786. X    sndpkt[i++] = smark;        /* Packet mark */
  1787. X    k = i++;                /* Remember this place */
  1788. X    sndpkt[i++] = tochar(n);        /* Sequence number */
  1789. X    sndpkt[i++] = type;            /* Packet type */
  1790. X    j = len + bctu;            /* True length */
  1791. X    if (j > 95) {            /* Long packet? */
  1792. X    sndpkt[k] = tochar(0);        /* Set LEN to 0 */
  1793. X    sndpkt[i++] = tochar(j / 95);    /* High part of length */
  1794. X    sndpkt[i++] = tochar(j % 95);    /* Low part of length */
  1795. X    sndpkt[i] = '\0';        /* Header checksum */
  1796. X    sndpkt[i++] = tochar(chk1(sndpkt+k));
  1797. X    } else
  1798. X    sndpkt[k] = tochar(j+2);    /* True length. */
  1799. X
  1800. X    for (j = len; j > 0; j--) {        /* Data */
  1801. X    sndpkt[i++] = *d++;
  1802. X    }
  1803. X    sndpkt[i] = '\0';            /* Null terminate. */
  1804. X    switch (bctu) {
  1805. X    case 1:                /* Type 1 - 6 bit checksum */
  1806. X        sndpkt[i++] = tochar(chk1(sndpkt+k));
  1807. X        break;
  1808. X    case 2:                /* Type 2 - 12 bit checksum */
  1809. X        j = chksum(sndpkt+k);
  1810. X        sndpkt[i++] = tochar((j >> 6) & 077);
  1811. X        sndpkt[i++] = tochar(j & 077);
  1812. X        break;
  1813. X    case 3:                /* Type 3 - 16 bit CRC-CCITT */
  1814. X        j = chk3(sndpkt + k);
  1815. X        sndpkt[i++] = tochar((j >> 12) & 017);
  1816. X        sndpkt[i++] = tochar((j >> 6) & 077);
  1817. X        sndpkt[i++] = tochar(j & 077);
  1818. X        break;
  1819. X    }
  1820. X    sndpkt[i++] = seol;            /* End of line */
  1821. X    sndpkt[i] = '\0';            /* Null string-terminator. */
  1822. X    sndpkl = i;                /* Remember length. */
  1823. X    i = ttol(sndpkt,sndpkl);        /* Send the packet. */
  1824. X    if (local && !xflag) tchar('.');
  1825. X    return(i);
  1826. X}
  1827. X
  1828. Xstatic
  1829. Xresend() {
  1830. X    int x;
  1831. X    if (*sndpkt)
  1832. X    x = ttol(sndpkt,sndpkl);    /* Send previous packet */
  1833. X    else
  1834. X    x = nak();            /* or NAK if none */
  1835. X    if (local && !xflag) tchar('%');    /* Let the user know. */
  1836. X    return(x);
  1837. X}
  1838. X
  1839. Xchk1(packet) char *packet; {        /* Compute Kermit's */
  1840. X    int s, t;                /* 1-character block check. */
  1841. X    s = chksum(packet);            /* Get the arithmetic sum. */
  1842. X    t = (((s & 192) >> 6) + s) & 63;    /* Fold it into 6 bits. */
  1843. X    return(t);
  1844. X}
  1845. X
  1846. Xstatic
  1847. Xchksum(p) char *p; {            /* Compute the checksum. */
  1848. X    unsigned m;
  1849. X    long s;
  1850. X
  1851. X    m = (parity) ? 0177 : 0377;        /* Mask for parity bit.    */
  1852. X    s = 0;
  1853. X    for (; *p != '\0'; p++)        /* For each character, */
  1854. X    s += *p & m;            /* accumulate the sum, */
  1855. X    return(s & 07777);            /* and then return it. */
  1856. X}
  1857. X
  1858. X/*
  1859. X * rpack reads a packet and returns the packet type, or else Q if the
  1860. X * packet was invalid, or T if a timeout occured.   Upon successful return,
  1861. X * sets the global variables:
  1862. X *    rsn    - the received sequence number
  1863. X *    rln    - length of the received data field
  1864. X *    rdatap    - a pointer to the null-terminated contents of the data field
  1865. X */
  1866. Xstatic
  1867. Xrpack() {
  1868. X    int i, j, x, type, rlnpos;
  1869. X    char pbc[4];            /* Packet block check. */
  1870. X
  1871. X    rsn = rln = -1;            /* In case of failure. */
  1872. X
  1873. X    *rcvpkt = '\0';            /* Initialize receive buffer. */
  1874. X    j = ttinl(rcvpkt,MAXRP,reol,stimo); /* Try to get a "line". */
  1875. X    if (j < 0) return('T');        /* Timed out. */
  1876. X
  1877. X    for (i = 0; rcvpkt[i] != rmark && (i < j); i++)    /* Find mark. */
  1878. X    ;
  1879. X    if (i == j) return('Q');        /* If no mark, bad packet. */
  1880. X
  1881. X    rlnpos = ++i;            /* Got it, remember position. */
  1882. X    if ((j = unchar(rcvpkt[i++])) == 0) { /* Long packet? */
  1883. X        j = rlnpos + 5;            /* Yes, check header */
  1884. X        if (j > MAXRP) return('Q');    /* Be defensive. */
  1885. X        x = rcvpkt[j];            /* Remember header checksum */
  1886. X        rcvpkt[j] = '\0';
  1887. X        if (unchar(x) != chk1(rcvpkt+rlnpos))    /* Check header */
  1888. X        return('Q');
  1889. X    rcvpkt[j] = x;            /* Restore packet */
  1890. X    rln = unchar(rcvpkt[j-2]) * 95 + unchar(rcvpkt[j-1]) - bctu;
  1891. X    j = 3;
  1892. X    } else {
  1893. X    rln = j - bctu - 2;        /* Regular packet */
  1894. X    j = 0;                /* No extended header */
  1895. X    }
  1896. X    rsn = unchar(rcvpkt[i++]);        /* Sequence number. */
  1897. X    type = rcvpkt[i++];            /* Packet type */
  1898. X    i += j;                /* Skip extended header, if any */
  1899. X    rdatap = rcvpkt + i;        /* The data itself. */
  1900. X    j = rln + i;            /* Position of block check. */
  1901. X    if (j > MAXRP)
  1902. X    return('Q');            /* Be defensive! */
  1903. X    for (x = 0; x < bctu; x++)        /* Copy the block check. */
  1904. X    pbc[x] = rcvpkt[j+x];
  1905. X    rcvpkt[j] = '\0';
  1906. X    switch (bctu) {            /* Which block check type? */
  1907. X    case 1:
  1908. X        if (unchar(*pbc) != chk1(rcvpkt+rlnpos)) return('Q');
  1909. X        break;
  1910. X    case 2:
  1911. X        x = unchar(*pbc) << 6 | unchar(pbc[1]);
  1912. X        if (x != chksum(rcvpkt+rlnpos)) return('Q');
  1913. X    case 3:
  1914. X        x = unchar(*pbc) << 12 | unchar(pbc[1]) << 6 | unchar(pbc[2]);
  1915. X        if (x != chk3(rcvpkt+rlnpos)) return('Q');
  1916. X        break;
  1917. X    default:
  1918. X        error("Impossible block check type.");
  1919. X    }
  1920. X    return type;            /* Otherwise, return packet type */
  1921. X}
  1922. X
  1923. X/*
  1924. X * CHK3
  1925. X * Calculate the 16-bit CRC of a null-terminated string using a
  1926. X * byte-oriented tableless algorithm devised by Andy Lowry (Columbia
  1927. X * University).  The magic number 010201 is derived from the CRC-CCITT
  1928. X * polynomial x^16+x^12+x^5+1.
  1929. X */
  1930. Xstatic
  1931. Xchk3(s) char *s; {
  1932. X    unsigned int c, q;
  1933. X    long crc = 0;
  1934. X
  1935. X    while ((c = *s++) != '\0') {
  1936. X    if (parity) c &= 0177;
  1937. X    q = (crc ^ c) & 017;        /* Low order nybble */
  1938. X    crc = (crc >> 4) ^ (q * 010201);
  1939. X    q = (crc ^ (c >> 4)) & 017;    /* High order nybble */
  1940. X    crc = (crc >> 4) ^ (q * 010201);
  1941. X    }
  1942. X    return(crc);
  1943. X}
  1944. X
  1945. X/*
  1946. X * getpkt--Fill a packet to the maximum.  Result goes in local data array
  1947. X * whose current length is indicated in global size.
  1948. X */
  1949. Xstatic
  1950. Xgetpkt(maxlen) int maxlen; {
  1951. X    int i, next;
  1952. X    static int c;
  1953. X    static char remain[6] = {'\0', '\0', '\0', '\0', '\0', '\0'};
  1954. X    void encode();
  1955. X    
  1956. X    if (first == 1) {            /* If first time thru... */
  1957. X    first = 0;            /* remember not to do this next time, */
  1958. X    remain[0] = '\0';        /* discard any old leftovers, */
  1959. X    c = gnchar();            /* get first character of file */
  1960. X    if (c < 0) {            /* watching out for null file */
  1961. X        first = -1;
  1962. X        return(size = 0);
  1963. X    }
  1964. X    } else if (first == -1) {        /* EOF from last time? */
  1965. X    return(size = 0);
  1966. X    }
  1967. X    
  1968. X
  1969. X/* Copy any leftovers that didn't fit in the last packet. */
  1970. X
  1971. X    for (size = 0; (data[size] = remain[size]) != '\0'; size++)
  1972. X    ;
  1973. X    *remain = '\0';
  1974. X
  1975. X/* Get, encode, and deposit the next character. */
  1976. X
  1977. X    rpt = 0;                /* Initialize repeat counter. */
  1978. X    
  1979. X    while (first > -1) {        /* Until end of file or string... */
  1980. X    next = gnchar();        /* Look ahead one character */
  1981. X    if (next < 0) first = -1;    /* If none, we're at EOF. */
  1982. X    osize = size;            /* Remember current size. */
  1983. X    encode(c, next);        /* Encode the character. */
  1984. X    c = next;            /* Old next char is now current. */
  1985. X    if (size == maxlen) return(size); /* If just at end, done. */
  1986. X    if (size > maxlen) {        /* Past end, must save some. */
  1987. X        for (i = 0; (remain[i] = data[osize+i]) != '\0'; i++)
  1988. X        ;
  1989. X        size = osize;
  1990. X        data[size] = '\0';
  1991. X        return(size);        /* Return size. */
  1992. X    }
  1993. X    }
  1994. X    return(size);            /* EOF, return size. */
  1995. X}
  1996. X
  1997. Xstatic
  1998. Xgnchar() {
  1999. X   char c;
  2000. X
  2001. X    if (isp) {                /* From string in memory */
  2002. X    return((c = *isp++) > 0 ? c : -1);
  2003. X    } else
  2004. X    return(zgetc(text));        /* or from a file. */
  2005. X}
  2006. X
  2007. X/*
  2008. X * Encodes the character a into the global data array,
  2009. X * and the global size is updated.
  2010. X * Global sctlq is the control prefix for sending data.
  2011. X */
  2012. Xstatic void
  2013. Xencode(a, next) char a; int next; {
  2014. X    int a7, b8;
  2015. X
  2016. X    if (rptflg) {            /* Doing run-length encoding? */
  2017. X    if (a == next) {        /* Yes, got a run? */
  2018. X        if (++rpt < 94) {        /* Yes count. */
  2019. X        return;
  2020. X        } else if (rpt == 94) {    /* If at maximum */
  2021. X        data[size++] = rptq;    /* Emit prefix, */
  2022. X        data[size++] = tochar(rpt); /* and count, */
  2023. X        rpt = 0;        /* and reset counter. */
  2024. X        }
  2025. X    } else if (rpt == 1) {        /* Run broken, only two? */
  2026. X        rpt = 0;            /* Yes, do the character wice */
  2027. X        encode(a,-1);        /* by calling self recursively. */
  2028. X        if (size <= maxsiz) osize = size; /* Watch for boundary */
  2029. X        rpt = 0;            /* Call self second time. */
  2030. X        encode(a,-1);
  2031. X        return;
  2032. X    } else if (rpt > 1) {        /* Run broken, more than two? */
  2033. X        data[size++] = rptq;    /* Yes, emit prefix and count */
  2034. X        data[size++] = tochar(++rpt);
  2035. X        rpt = 0;            /* and reset counter. */
  2036. X    }
  2037. X    }
  2038. X    a7 = a & 127;            /* Isolate low 7 bits */
  2039. X    b8 = a & 128;            /* And "parity" bit */
  2040. X
  2041. X    if (ebqflg & b8) {            /* If doing 8th-bit prefixing */
  2042. X    data[size++] = ebq;        /* and 8th bit on, insert prefix */
  2043. X    a = a7;                /* and clear the 8th bit. */
  2044. X    }
  2045. X    if (a7 < 32 || a7 == 127) {        /* If control character */
  2046. X    data[size++] = sctlq;        /* insert control quote */
  2047. X    a = ctl(a);            /* and make printable. */
  2048. X    } else if (a7 == sctlq)        /* If data is control prefix, */
  2049. X    data[size++] = sctlq;        /* prefix it. */
  2050. X    else if (ebqflg && a7 == ebq)    /* If doing 8th-bit prefixing, */
  2051. X    data[size++] = sctlq;        /* ditto for 8th-bit prefix. */
  2052. X    else if (rptflg && a7 == rptq)    /* If doing run-length encoding, */
  2053. X    data[size++] = sctlq;        /* ditto for repeat prefix. */
  2054. X
  2055. X    data[size++] = a;            /* Finally, emit the character. */
  2056. X    data[size] = '\0';            /* Terminate string. */
  2057. X}
  2058. X
  2059. X/*
  2060. X * Decodes the data pointed to by the global pointer rdatap.
  2061. X */
  2062. Xstatic
  2063. Xdecode() {
  2064. X    int a, a7, b8;
  2065. X
  2066. X    while ((a = *rdatap++) != '\0') {
  2067. X    rpt = 1;            /* Initialize repeat count. */
  2068. X    if (rptflg) {            /* Repeat processing? */
  2069. X        if (a == rptq) {        /* Yes, have repat prefix? */
  2070. X        rpt = unchar(*rdatap++); /* Yes, get count. */
  2071. X        a = *rdatap++;        /* and following character. */
  2072. X        }
  2073. X    }
  2074. X    b8 = 0;                /* Assume 8th bit not on. */
  2075. X    if (ebqflg) {            /* Doing 8th-bit prefixing? */
  2076. X        if (a == ebq) {        /* Yes, have 8th-bit prefix? */
  2077. X        b8 = 128;        /* Yes, remember bit 8 on */
  2078. X        a = *rdatap++;        /* and get following character. */
  2079. X        }
  2080. X    }
  2081. X    if (a == rctlq) {        /* Is it control prefix? */
  2082. X        a = *rdatap++;        /* Yes, get next character */
  2083. X        a7 = a & 127;        /* and its low 7 bits. */
  2084. X        if (a7 > 62 && a7 < 96)    /* Encoded control character? */
  2085. X            a = ctl(a);        /* Yes, controllify */
  2086. X    }
  2087. X    a |= b8;            /* OR in the 8th bit. */
  2088. X    for (; rpt > 0; rpt--)
  2089. X        if (pnchar(a) < 0) return -1; /* Output the character. */
  2090. X    }
  2091. X    return(0);
  2092. X}
  2093. X
  2094. Xstatic
  2095. Xpnchar(c) int c; {            /* Put next character. */
  2096. X    if (xflag) {            /* To screen if desired. */
  2097. X    tchar(c);
  2098. X    return(1);
  2099. X    } else if (osp) {            /* Or to string in memory... */
  2100. X    *osp++ = c;
  2101. X    return(1);
  2102. X    } else return(zputc(c,text));    /* Otherwise to file. */
  2103. X}
  2104. X
  2105. Xstatic
  2106. Xencstr(s) char *s; {            /* Fill a packet from the string */
  2107. X    first = 1;                /* Start lookahead. */
  2108. X    isp = s;                /* Set input string pointer */
  2109. X    (void) getpkt(spsiz);        /* Fill a packet */
  2110. X    isp = NULL;                /* Reset input string pointer */
  2111. X    return(size);            /* Return data field length */
  2112. X}
  2113. X
  2114. Xstatic void
  2115. Xdecstr(s) char *s; {            /* Decode packet data into a string */
  2116. X    osp = s;                /* Set output string pointer */
  2117. X    (void) decode();            /* Decode the string */
  2118. X    *osp = '\0';            /* Terminate the string */
  2119. X    osp = NULL;                /* Reset output string pointer */
  2120. X}
  2121. X
  2122. Xstatic void
  2123. Xspar(s) char *s; {            /* Set parameters */
  2124. X    int x;
  2125. X
  2126. X    s--;                /* Line up with field numbers. */
  2127. X    
  2128. X    /* Limit on size of outbound packets */
  2129. X    x = (rln >= 1) ? unchar(s[1]) : 80;
  2130. X    spsiz = (x < 10) ? 80 : x;
  2131. X
  2132. X    /* Timeout on inbound packets */
  2133. X    x = (rln >= 2) ? unchar(s[2]) : 5;
  2134. X    stimo = (x < 0) ? 5 : x;
  2135. X
  2136. X    
  2137. X    /* Outbound padding */
  2138. X    spadn = 0; spadc = '\0';
  2139. X    if (rln >= 3) {
  2140. X    spadn = unchar(s[3]);
  2141. X    if (rln >= 4)
  2142. X        spadc = ctl(s[4]);
  2143. X    }
  2144. X    
  2145. X    /* Outbound packet terminator */
  2146. X    seol = (rln >= 5) ? unchar(s[5]) : '\r';
  2147. X    if (seol < 2 || seol > 31) seol = '\r';
  2148. X    
  2149. X    /* Control prefix */
  2150. X    x = (rln >= 6) ? s[6] : '#';
  2151. X    rctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
  2152. X    
  2153. X    /* 8th-bit quoting */
  2154. X    rq = (rln >= 7) ? s[7] : 0;
  2155. X    if (rq == 'Y') rqf = 1;
  2156. X    else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
  2157. X    else rqf = 0;
  2158. X    
  2159. X    switch (rqf) {
  2160. X    case 0: ebqflg = 0; break;
  2161. X    case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
  2162. X    case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
  2163. X    }
  2164. X
  2165. X    /* Block check */
  2166. X    x = 1;
  2167. X    if (rln >= 8) {
  2168. X    x = s[8] - '0';
  2169. X    if (x < 1 || x > 3) x = 1;
  2170. X    }
  2171. X    bctr = x;
  2172. X
  2173. X    /* Repeat prefix */
  2174. X    if (rln >= 9) {
  2175. X    rptq = s[9];
  2176. X    rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
  2177. X    } else rptflg = 0;
  2178. X
  2179. X    /* Capabilities */
  2180. X    atcapu = lpcapu = swcapu = 0;    /* No capabilities by default    */
  2181. X    if (rln >= 10) {
  2182. X    x = unchar(s[10]);
  2183. X    atcapu = (x & atcapb) && atcapr;    /* Attribute packets */
  2184. X    lpcapu = (x & lpcapb) && lpcapr;    /* Long packets */
  2185. X    swcapu = (x & swcapb) && swcapr;    /* Sliding windows */
  2186. X    for (capas = 10; (unchar(s[capas]) & 1) && (rln >= capas); capas++)
  2187. X        ;                    /* Skip to capas + 1 */
  2188. X    }
  2189. X
  2190. X    /* Long packets */
  2191. X    if (lpcapu) {            /* Flag set above */
  2192. X    if (rln > capas+2) {
  2193. X        x = unchar(s[capas+2]) * 95 + unchar(s[capas+3]);
  2194. X        spsiz = x > MAXSP ? MAXSP : x;
  2195. X    }
  2196. X    /* else a fatal error, but how do we terminate? */
  2197. X    }
  2198. X
  2199. X    /* Sliding windows */
  2200. X    if (swcapu) {
  2201. X    if (rln > capas+1) {
  2202. X        x = unchar(s[capas+1]);
  2203. X        wsize = x > MAXWS ? MAXWS : x;
  2204. X    } else
  2205. X        wsize = 1;
  2206. X    }
  2207. X}
  2208. X
  2209. X/* Fill the array with my send-init parameters */
  2210. X
  2211. Xstatic char *
  2212. Xrpar() {
  2213. X    data[1] = tochar(DRPSIZ);        /* Biggest packet I can receive */
  2214. X    data[2] = tochar(rtimo);        /* When I want to be timed out */
  2215. X    data[3] = tochar(rpadn);        /* How much padding I need */
  2216. X    data[4] = ctl(rpadc);        /* Padding character I want */
  2217. X    data[5] = tochar(reol);        /* End-of-Line character I want */
  2218. X    data[6] = sctlq;            /* Control-Quote character I send */
  2219. X    switch(rqf) {            /* 8th-bit prefix */
  2220. X    case -1:
  2221. X    case  1: if (parity) ebq = sq = '&'; break;
  2222. X    case  0:
  2223. X    case  2: break;
  2224. X    }
  2225. X    data[7] = sq;
  2226. X    data[8] = bctr + '0';        /* Block Check Type */
  2227. X    if (rptflg) data[9] = rptq; else data[9] = '~';
  2228. X    data[10] = tochar(atcapr?atcapb:0 | lpcapr?lpcapb:0 | swcapr?swcapb:0);
  2229. X    capas = 10;
  2230. X    data[capas+1] = tochar(swcapr ? wsize : 0);    /* Window size */
  2231. X    data[capas+2] = tochar(rpsiz / 95);    /* Long packet size */
  2232. X    data[capas+3] = tochar(rpsiz % 95);    /* ... */
  2233. X    data[capas+4] = '\0';
  2234. X    return(data+1);            /* Return a pointer to the string */
  2235. X}
  2236. X
  2237. X/*
  2238. X * proto()--Kermit protocol entry point.  Set your start state and call
  2239. X * this, NOT wart().  Modified to set long packets capability on the
  2240. X * basis of the packet size set in the external user interface.
  2241. X */
  2242. Xvoid
  2243. Xproto()
  2244. X{
  2245. X    void *malloc();
  2246. X
  2247. X    sndpkt = (char *) malloc((unsigned) (MAXSP+200));
  2248. X    rcvpkt = (char *) malloc((unsigned) (MAXRP+100));
  2249. X    data = (char *) malloc((unsigned) (MAXSP+1));
  2250. X    if (urpsiz > 94) {                /* Long packets? */
  2251. X    rpsiz = (urpsiz > MAXRP - 20 ? MAXRP - 20 : urpsiz);
  2252. X    lpcapr = 1;                /* Request long packets */
  2253. X    bctr = 3;                /* And 16 bit CRC's    */
  2254. X    } else {                    /* No long packets */
  2255. X    lpcapr = 0;
  2256. X    bctr = 1;                /* Drop back to type 1    */
  2257. X    if (urpsiz < 10)            /* Too small?    */
  2258. X        rpsiz = 80;
  2259. X    else
  2260. X        rpsiz = DRPSIZ;
  2261. X    }
  2262. X    cx = cz = 0;                /* Haven't aborted yet */
  2263. X    if (sndpkt == NULL || rcvpkt == NULL || data == NULL)
  2264. X    tmsgl("Can't allocate memory for Kermit!!");
  2265. X    else
  2266. X    wart();
  2267. X    if (sndpkt) free(sndpkt);
  2268. X    if (rcvpkt) free(rcvpkt);
  2269. X    if (data) free(data);
  2270. X}
  2271. X    
  2272. X/*
  2273. X * That ends the system-independent Kermit modules.  What follows
  2274. X * are the system-dependent ones.
  2275. X */
  2276. X
  2277. X/*
  2278. X * Now for the file routines.  I chose to use the z...() routines
  2279. X * written in terms of stdio.
  2280. X */
  2281. X
  2282. X#include <stdio.h>
  2283. X
  2284. Xstatic FILE *ifp = NULL, *ofp = NULL;
  2285. X
  2286. Xstatic
  2287. Xzopeni(name) char *name; {
  2288. X    ifp = fopen(name, "r");
  2289. X    if (ifp == NULL)
  2290. X    return -1;
  2291. X    else
  2292. X    return 0;
  2293. X}
  2294. X
  2295. Xstatic
  2296. Xzopeno(name) char *name; {
  2297. X    ofp = fopen(name, "w");
  2298. X    if (ofp == NULL)
  2299. X    return -1;
  2300. X    else
  2301. X    return 0;
  2302. X}
  2303. X
  2304. Xstatic
  2305. Xzclosi() {
  2306. X    int x;
  2307. X
  2308. X    if (ifp == NULL)
  2309. X    return 0;
  2310. X    x = fclose(ifp);
  2311. X    ifp = NULL;
  2312. X    if (x < 0)
  2313. X    return -1;
  2314. X    else
  2315. X    return 0;
  2316. X}
  2317. X
  2318. Xstatic
  2319. Xzcloso(discard) int discard; {
  2320. X    int x;
  2321. X
  2322. X    if (ofp == NULL)
  2323. X    return 0;
  2324. X    x = fclose(ofp);
  2325. X    ofp = NULL;
  2326. X    if (x < 0)
  2327. X    return -1;
  2328. X    else if (discard)
  2329. X    if (unlink(filnam) < 0)
  2330. X        return -1;
  2331. X    return 0;
  2332. X}
  2333. X
  2334. X#include <ctype.h>
  2335. X
  2336. Xextern int convert;        /* 0 for literal files, 1 for translate */
  2337. X
  2338. Xstatic void
  2339. Xzrtol(s1,s2,warn) char *s1, *s2; int warn; {
  2340. X    strcpy(s2,s1);        /* for now */
  2341. X    if (convert)
  2342. X    while (*s2 != '\0') {
  2343. X        if (isalpha(*s2))
  2344. X        *s2 = tolower(*s2);
  2345. X        s2++;
  2346. X    }
  2347. X}
  2348. X
  2349. Xstatic void
  2350. Xzltor(s1,s2) char *s1, *s2; {
  2351. X    char dotseen = 0;
  2352. X
  2353. X    if (!convert)
  2354. X    strcpy(s2, s1);
  2355. X    else {
  2356. X    while (*s1 != '\0') {
  2357. X        if (islower(*s1))
  2358. X        *s2 = toupper(*s1);
  2359. X        else if (isalnum(*s1))
  2360. X        *s2 = *s1;
  2361. X        else if (*s1 == '.')
  2362. X        if (!dotseen) {
  2363. X            dotseen = 1;
  2364. X            *s2 = *s1;
  2365. X        } else
  2366. X            *s2 = 'X';
  2367. X        /* else a character we're not prepared to handle. */
  2368. X        s1++; s2++;
  2369. X        }
  2370. X    *s2 = '\0';
  2371. X    }
  2372. X}
  2373. X
  2374. X/*
  2375. X * System-dependent function to return next character from file.
  2376. X * If the text flag argument is nonzero, first convert to canonic form. 
  2377. X */
  2378. Xstatic
  2379. Xzgetc(text) {                /* Get next char from file. */
  2380. X#define MAXREC 100            /* Size of record buffer. */
  2381. X
  2382. X    static char recbuf[MAXREC + 1];    /* Big enough for MAXREC newlines */
  2383. X    static char *rbp;            /* Buffer pointer */
  2384. X    static int i = 0;            /* Buffer char counter */
  2385. X    int c;
  2386. X
  2387. X    if (i == 0) {            /* If the buffer is empty, */
  2388. X                    /* read next line from file. */
  2389. X    for (i = 0;
  2390. X         i < MAXREC - 1 && (c = getc(ifp)) != EOF && c != '\n';
  2391. X         i++)
  2392. X        recbuf[i] = c;
  2393. X    if (c == '\n') {        /* Got newline        */
  2394. X        if (text) {            /* If in text mode    */
  2395. X        recbuf[i++] = '\r';    /* Substitute CRLF    */
  2396. X        }
  2397. X        recbuf[i++] = c;
  2398. X    }
  2399. X    recbuf[i] = '\0';        /* Done, terminate buffer */
  2400. X    if (i == 0) return -1;        /* If empty, indicate EOF */
  2401. X    rbp = recbuf;            /* Remember position for next time */
  2402. X    }
  2403. X    i--;                /* Adjust the counter. */
  2404. X    return(*rbp++ & 0377);        /* Return hext character */
  2405. X}
  2406. X
  2407. Xstatic
  2408. Xzputc(c, text) int c, text; {        /* Put character in file. */
  2409. X    unsigned int x;
  2410. X
  2411. X    c &= 255;                /* Undo any sign extension */
  2412. X    if (text && c == '\r')        /* If in text mode, */
  2413. X        return 0;            /* eliminate carriage returns. */
  2414. X    else {                /* Otherwise, */
  2415. X    x = putc(c, ofp) & 255;        /* output the character. */
  2416. X    if (c == 255) return 0;        /* Special handling for all 1's */
  2417. X    return ((x != c) ? -1 : 0);    /* Normal return code. */
  2418. X    }
  2419. X}
  2420. SHAR_EOF
  2421. echo "End of archive 6 (of 9)"
  2422. # if you want to concatenate archives, remove anything after this line
  2423. exit
  2424.